import { isObject, isHTMLTag } from "../utils/index";

// 生成虚拟标签节点
export function createElement(vm, tag, data = {}, ...children) {
	const key = data.key;
	if (key) {
		delete data.key;
	}
	// 判断是不是真实html标签
	if (isHTMLTag(tag)) {
		// 返回真实dom标签的虚拟节点
		return vNode(tag, data, key, children, undefined);
	} else {
		// 获取自定义组件
		let Ctor = vm.$options.components[tag];
		// 返回自定义组件虚拟节点
		return createComponentVNode(vm, tag, data, key, children, Ctor);
	}
}

// 创建自定义组件的虚拟节点
function createComponentVNode(vm, tag, data, key, children, Ctor) {
	// 如果找到的是对象
	if (isObject(Ctor)) {
		// 调用extend方法把对象变成子类构造方法
		Ctor = vm.$options._base.extend(Ctor);
	}
	// 定义组件内部的方法
	data.hook = {
		init(vNode) {
			// 实例化组件,componentsInstance是当前组件的实例,_isComponent标识是组件
			const child = (vNode.componentsInstance = new Ctor({
				_isComponent: true,
			}));
			// 调用组件自己的挂载方法
			child.$mount();
		},
	};
	// 生成组件的虚拟节点
	return vNode(`vue-component-${Ctor.cid}-${tag}`, data, key, undefined, {
		Ctor,
		children,
	});
}

// 生成虚拟文本节点
export function createTextNode(text) {
	return vNode(undefined, undefined, undefined, undefined, text);
}

// 虚拟节点就是通过_c _v _s实现用对象来描述dom
// template -> ast -> renter -> update -> dom
function vNode(tag, data, key, children, text, componentOptions) {
	return {
		tag,
		data,
		key,
		children,
		text,
		componentOptions,
	};
}
